import java.util.Vector;

/**
 * @author Patrick 
 * Sub-class of PtrGrpType. FuncPtr type contains the name and size. 
 */
public class FuncPtrType extends PtrGrpType {
	
	private Type returnType;
	private Vector<STO> paramList;
	private boolean hasReturnStmt;
	private boolean isReturnByRef;
	
	/*
	 * Default ctor that creates an FuncPtrtType object with
	 * name "funcptr" and size of 4 (bytes).
	 */
	public FuncPtrType() {
		super("funcptr"); // call PtrGrpType ctor
	}
	
	public FuncPtrType(String strName) {
		super(strName); // call PtrGrpType ctor
	}
	
	public FuncPtrType(Type retType, Vector<STO> paramList, boolean isReturnByRef) {
		setReturnType(retType);
		setParamList(paramList);
		setReturnByRef(isReturnByRef);
	}
	
	@Override
	public String getName() {
		if(isTypedef()) {
			return super.getName();
		}
		String s = "funcptr : " + getReturnType().getName() + " ";
		String newString;
		if(isReturnByRef()) {
			s += "& ";
		}
		s += "(";
		newString = s;
		Vector<STO> paramList = getParamList();
		if(paramList != null) {
			for(int i = 0; i < paramList.size(); i++) {
				s += paramList.get(i).getType().getName();
				s += " ";
				if(((VarSTO)paramList.get(i)).isRef()) {
					s += "&";
				}
				s += paramList.get(i).getName();
				s += ", ";
			}
			newString = s.substring(0, s.length()-2);
		}
		newString += ")";
		return newString;
	}
	
	@Override
	public boolean isFuncPtrType () { 
		return true; 
	}

	public Type getReturnType() {
		return returnType;
	}

	public void setReturnType(Type returnType) {
		this.returnType = returnType;
	}

	public Vector<STO> getParamList() {
		return paramList;
	}

	public void setParamList(Vector<STO> paramList) {
		this.paramList = paramList;
	}

	public boolean hasReturnStmt() {
		return hasReturnStmt;
	}

	public void setHasReturnStmt(boolean hasReturnStmt) {
		this.hasReturnStmt = hasReturnStmt;
	}

	public boolean isReturnByRef() {
		return isReturnByRef;
	}

	public void setReturnByRef(boolean isReturnByRef) {
		this.isReturnByRef = isReturnByRef;
	}
	
	public boolean isAssignableTo(Type t) {
		if(t.isFuncPtrType()) {
			// check paramList, etc
			FuncPtrType other = (FuncPtrType)t;
			Vector<STO> thisParam = getParamList();
			Vector<STO> otherParam = other.getParamList();
			
			// check paramList
			if((thisParam != null) && (otherParam != null)) {
				if(thisParam.size() != otherParam.size()) {
					return false;
				}
				else {
					for(int i = 0; i < otherParam.size(); i++) {
						if(thisParam.get(i).getType().isEquivalentTo(otherParam.get(i).getType())) {
							if(((VarSTO)thisParam.get(i)).isRef() != ((VarSTO)otherParam.get(i)).isRef()) {
								return false;
							}
						}
						else {
							
							return false;
						}
					}
				}
			}
			// num of params differ
			else if((thisParam == null) && (otherParam != null)) {
				return false;
			}
			else if((thisParam != null) && (otherParam == null)) {
				return false;
			}
			if(!getReturnType().isEquivalentTo(other.getReturnType())) {
				if(!(getReturnType().isVoid() && getReturnType().isVoid())) { 
					return false;
				}
			}
			if(isReturnByRef() != other.isReturnByRef()) {
				return false;
			}
			return true;
		}
		return false;
	}
	
	public boolean isEquivalentTo(Type t) {
		if(t.isNullPtrType()) {
			return true;
		} else {
			return isAssignableTo(t);
		}
	}
}
